/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/*
* JLikeliHood.java
*
* Created on November 22, 2007, 9:11 AM
*
* To change this template, choose Tools | Template Manager
* and open the template in the editor.
 */
package genomemap.worker;

import genomemap.data.DataSource;
import genomemap.data.JDataSource;

import gui.genomemap.inputModel.ComJLHoodIModel;

import javautil.collections.ArrayUtil;
import javautil.collections.ListUtil;
import javautil.io.LogUtil;

import java.util.Hashtable;
import java.util.List;
import java.util.Map;

/**
 * Joint Likelihood. This is a negative-log likelihood.
 * Defined as:  PLikeliHood - GlikeliHood
 * (Because PLikeliHood is a negative-log-likelihood and GlikeliHood
 * is a positive-log-likelihood.
 * @author stewari1
 */
public class JLikeliHood extends LHood {

    /** Field description */
    private GLikeliHood gHood = null;

    /**
     * joint data source (GDataSource and PDataSource )
     */
    private JDataSource jData = null;

    /** Field description */
    private PLikeliHood pHood = null;

    /** Field description */
    private int gIterationLimit = 150;

    /**
     * convergence for the genetic part
     */
    private double gConvgEpsilon = 1.0E-4;

    /**
     * implement caching for GHood: key: gene order value: lhood
     */
    private final Map<List<Integer>, GLikeliHood> gHoodCache = new Hashtable<>();

    /** Creates a new instance of JLikeliHood */
    public JLikeliHood() {}

    /**
     * Constructs ...
     *
     * @param inputModel description
     */
    public JLikeliHood(ComJLHoodIModel inputModel) {

        setGIterationLimit(inputModel.getGIterationLimit());
        setGConvgEpsilon(inputModel.getGConvgEpsilon());

        jData = DataSource.getJDataSource(inputModel.getLinkageGroup(), inputModel.getOrder());

        jData.getGData().setRflpImputation(inputModel.getRflpImputation());
        setJData(jData);
    }

    public static void main(String[] args) {

        JLikeliHood jHood = new JLikeliHood();

        jHood.setJData(DataSource.getJDataSource(1, new int[] {
            1, 2, 3, 4, 5, 6, 7
        }));
        jHood.setVerbose(false);
        jHood.runJHood();
        System.out.println("The joint log-likelihood is : " + jHood.getLhood());
        System.out.println("gene order: ");
        LogUtil.print(jHood.getJData().getGData().getOrder());
    }

    /**
     * computes the function which is used for simulated annealing
     */
    @Override
    public double compute() {

        getJData().setOrder(getOrder());

        return runJHood();
    }

    @Override
    public double initialValue() {
        return compute();
    }

    /**
     *
     * @param jData
     * @return
     */
    public double runJHood() {

        if (!jData.dataLoaded) jData.loadData();

        setStatusInfo("Joint Likleihood Computation has Started");
        setProgress(10);

        pHood = new PLikeliHood();

        pHood.setPData(jData.getPData());
        pHood.setParentWorker(this);
        pHood.setVerbose(isVerbose());

        gHood = new GLikeliHood();

        gHood.setConvgEpsilon(getGConvgEpsilon());
        gHood.setIterationLimit(getGIterationLimit());
        gHood.setGData(jData.getGData());
        gHood.setParentWorker(this);
        gHood.setVerbose(isVerbose());
        pHood.runPHood();
        setProgress(40);


        // look up gHoodCache
        GLikeliHood cachedGHood =
            gHoodCache.get(ListUtil.createArrayList(ArrayUtil.getIntegerArray(gHood.getOrder())));

        if (cachedGHood == null) {

            gHood.runGHood();
            gHoodCache.put(ListUtil.createArrayList(ArrayUtil.getIntegerArray(gHood.getOrder())),
                           gHood);

        } else {
            gHood = cachedGHood;
        }

        setProgress(100);
        setLhood(pHood.getLhood() - gHood.getLhood());
        setStatusInfo("The Joint Log-likelihood is " + getLhood());


        // System.out.println("Genetic Contribution: " + gHood.getLhood());
        return getLhood();
    }

    /**
     * joint data source (GDataSource and PDataSource )
     */
    public JDataSource getJData() {
        return jData;
    }

    /**
     * joint data source (GDataSource and PDataSource )
     *
     * @param newVal
     */
    @Override
    public void setJData(JDataSource jData) {

        this.jData = jData;

        setOrder(jData.getPData().getOrder());
    }

    int getGIterationLimit() {
        return gIterationLimit;
    }

    public void setGIterationLimit(int gIterationLimit) {
        this.gIterationLimit = gIterationLimit;
    }

    double getGConvgEpsilon() {
        return gConvgEpsilon;
    }

    public void setGConvgEpsilon(double gConvgEpsilon) {
        this.gConvgEpsilon = gConvgEpsilon;
    }

    public GLikeliHood getGHood() {
        return gHood;
    }

    public PLikeliHood getPHood() {
        return pHood;
    }

    @Override
    public double getLogLikeliHood() {
        return -getLhood();
    }
}
